using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

using Yorrick.FlickrMetadataSynchr.Data;
using Yorrick.FlickrMetadataSynchr.Properties;

namespace Yorrick.FlickrMetadataSynchr.Sync
{
    /// <summary>
    /// Class that can sync metadata information.
    /// </summary>
    internal class MetadataSyncher
    {
        #region Private constants
        #endregion

        #region Private fields
        /// <summary>
        /// The list of matched picture pairs on which this instance operates.
        /// </summary>
        IList<PicturePair> _picturePairs;

        /// <summary>
        /// The settings for the metadata sync strategy.
        /// </summary>
        SyncStrategySettings _strategySettings;
        #endregion

        #region Constructor
        /// <summary>
        /// Constructs an instance.
        /// </summary>
        /// <param name="picturePairs">A list of matched picture pairs on which to operate.</param>
        /// <param name="strategySettings">The settings for the metadata sync strategy.</param>
        public MetadataSyncher(IList<PicturePair> picturePairs, SyncStrategySettings strategySettings)
        {
            _picturePairs = picturePairs;
            _strategySettings = strategySettings;
        }
        #endregion

        #region Public properties
        /// <summary>
        /// Gets the list of picture pairs on which this instance operates.
        /// </summary>
        public IList<PicturePair> PicturePairs
        {
            get
            {
                return _picturePairs;
            }
        }
        #endregion

        #region Public methods
        /// <summary>
        /// Synchronizes the metadata in each picture pair.
        /// </summary>
        /// <param name="tagsSyncBehavior">Setting for how tags should be synced.</param>
        public void SyncPictures()
        {
            foreach (PicturePair picturePair in _picturePairs)
            {
                SynchronizePicturePair(picturePair);
            }
        }
        #endregion

        #region Public static methods
        /// <summary>
        /// Copies metadata from one metadata container to another.
        /// </summary>
        /// <param name="from">The source.</param>
        /// <param name="to">The destination.</param>
        public static void CopyMetadata(FlickrPictureMetadata from, LocalPictureMetadata to)
        {
            to.FlickrId = from.FlickrId;
            to.DateTaken = from.DateTaken;
            to.Author = from.Author;
            to.Title = from.Title;
            to.Description = from.Description;
            to.Tags = (string[])from.Tags.Clone();
            to.GpsLatitude = from.GpsLatitude;
            to.GpsLongitude = from.GpsLongitude;
        }
        #endregion

        #region Private methods
        /// <summary>
        /// Synchronizes the metadata in <paramref name="picturePair"/>.
        /// </summary>
        /// <param name="picturePair">The picture pair to synchronize.</param>
        private void SynchronizePicturePair(PicturePair picturePair)
        {
            MergeMetadata(picturePair);

            SetSyncDirection(picturePair);

            string syncDirectionMessage;

            switch (picturePair.SyncDirection)
            {
                case SyncDirection.FromFlickrToLocal:
                    syncDirectionMessage = "One-way sync Flickr -> local";
                    break;
                case SyncDirection.FromLocalToFlickr:
                    syncDirectionMessage = "One-way sync local -> Flickr";
                    break;
                case SyncDirection.None:
                case SyncDirection.NoSyncNeeded:
                    syncDirectionMessage = "No sync needed";
                    break;
                case SyncDirection.BothWays:
                    syncDirectionMessage = "Two-way sync Flickr <-> local";
                    break;
                default:
                    throw new InvalidOperationException("Unsupported sync direction.");
            }

            Trace.TraceInformation("{0} for {1} -> '{2}'.", syncDirectionMessage, picturePair.FlickrMetadata.FlickrId, picturePair.LocalMetadata.FilePath);
        }

        /// <summary>
        /// Merges metadata for a picture pair.
        /// </summary>
        /// <param name="picturePair ">A picture pair.</param>
        private void MergeMetadata(PicturePair picturePair)
        {
            LocalPictureMetadata lm = picturePair.LocalMetadata;
            FlickrPictureMetadata fm = picturePair.FlickrMetadata;

            MetadataMerger metadataMerger = new MetadataMerger(lm, fm, _strategySettings);

            metadataMerger.Merge();
        }

        /// <summary>
        /// Sets the direction in which metadata was changed.
        /// </summary>
        /// <param name="picturePair ">A picture pair.</param>
        private static void SetSyncDirection(PicturePair picturePair)
        {
            LocalPictureMetadata lm = picturePair.LocalMetadata;
            FlickrPictureMetadata fm = picturePair.FlickrMetadata;

            if (lm.Changed && fm.Changed)
            {
                picturePair.SyncDirection = SyncDirection.BothWays;
            }
            else if (lm.Changed)
            {
                picturePair.SyncDirection = SyncDirection.FromFlickrToLocal;
            }
            else if (fm.Changed)
            {
                picturePair.SyncDirection = SyncDirection.FromLocalToFlickr;
            }
            else
            {
                picturePair.SyncDirection = SyncDirection.NoSyncNeeded;
            }
        }
        #endregion
    }
}